﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

using AKMII.DMRA.Common;
using AKMII.DMRA.DataAccess;
using AKMII.DMRA.Business.Rule;
// Added by Andy 09/12/2010 for the task of ordering leads by Driving Directions
using MapPoint;
using System.Linq;
using AKMII.DMRA.Business.Service;
using System.Configuration;


namespace AKMII.DMRA.DataLoader
{
    public class Generator
    {
        public void Process()
        {
            List<Lead> leads = null;
            LeadAccessor leadAccessor = new LeadAccessor();

            try
            {
                Logger.Info("Insert leads ordered into temp table.");
                leadAccessor.InsertOrderedLeads(CurrentPeriod.Month, CurrentPeriod.Year);

                Logger.Info("Get leads ordered count from temp table.");
                int count = leadAccessor.GetOrderedLeadsCount();
                int pageSize = 1000;
                int totalCount = 0;

                foreach (var file in Directory.GetFiles(SystemConfiguration.CommonSetting.FolderForGeneratePrintingHouseFile))
                {
                    File.Delete(file);
                Logger.Info("Delete history file for printing house at " + file);
                }

                foreach (var file in Directory.GetFiles(SystemConfiguration.CommonSetting.FolderForGenerateDmraFile))
                {
                    File.Delete(file);
                    Logger.Info("Delete history file for DMRA at " + file);
                }

                for (int i = 0; i <= count / pageSize; i++)
                {
                    Logger.Info("Get leads ordered from temp table.");
                    leads = leadAccessor.GetOrderedLeads(i + 1, pageSize);

                    bool isNeedCreate = false;
                    if (i == 0)
                    {
                        isNeedCreate = true;
                    }

                    if (leads != null)
                    {
                        //Order the lead list
                        if (bool.Parse(ConfigurationManager.AppSettings["IsNeedOptimize"]))
                        {
                            MappointService mappoint = new MappointService();
                            leads = mappoint.CalculateRoute(leads);
                        }

                        Logger.Info("Start generate file for printing house.");
                        GenerateFileForPrintingHouse(leads,
                            SystemConfiguration.CommonSetting.FolderForGeneratePrintingHouseFile, isNeedCreate);

                        Logger.Info("Start generate file for DMRA.");
                        GenerateFileForDMRA(leads,
                            SystemConfiguration.CommonSetting.FolderForGenerateDmraFile, isNeedCreate);

                        totalCount += leads.Count;
                    }
                }

                Logger.Info("Generate file for " + totalCount.ToString() + " leads.");

                CommandHistoryAccessor accessor = new CommandHistoryAccessor();
                accessor.UpdateLastExecuteTime(Command.Generate.ToString(), DateTime.Now);

                Logger.Info("Clear temp table.");
                leadAccessor.RemoveOrderedLeads();
            }
            catch (Exception ex)
            {
                Logger.Error("Exception occurs in generate process", ex);
            }
            finally
            {
                if (leads != null)
                {
                    leads.Clear();
                }
            }
        }

        private void GenerateFileForPrintingHouse(List<Lead> leads, string directory, bool isNeedCreate)
        {
            if (leads != null && leads.Count > 0)
            {
                string fileName = Path.Combine(directory,
                    string.Format(Constants.FileNameForPrintingHouse, Utility.GetNumber(CurrentPeriod.Month), CurrentPeriod.Year.ToString()));
                StreamWriter sw = null;

                try
                {
                    if (isNeedCreate)
                    {
                        using (FileStream fs = new FileStream(fileName, FileMode.Create))
                        {
                            sw = new StreamWriter(fs);

                            foreach (Lead lead in leads)
                            {
                                sw.WriteLine(lead.RawData);
                            }

                            sw.Flush();
                            sw.Close();
                        }
                    }
                    else
                    {
                        using (FileStream fs = new FileStream(fileName, FileMode.Append))
                        {
                            sw = new StreamWriter(fs);

                            foreach (Lead lead in leads)
                            {
                                sw.WriteLine(lead.RawData);
                            }

                            sw.Flush();
                            sw.Close();
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw new ApplicationException("Exception occurs in generate file for printing house", ex);
                }
                finally
                {
                    if (sw != null)
                    {
                        sw.Dispose();
                    }
                }
            }
        }

        private void GenerateFileForDMRA(List<Lead> leads, string directory, bool isNeedCreate)
        {
            if (leads != null && leads.Count > 0)
            {
                string fileName = Path.Combine(directory,
                    string.Format(Constants.FileNameForDmra, Utility.GetNumber(CurrentPeriod.Month), CurrentPeriod.Year.ToString())); 
                StreamWriter sw = null;

                try
                {
                    if (isNeedCreate)
                    {
                        using (FileStream fs = new FileStream(fileName, FileMode.Create))
                        {
                            sw = new StreamWriter(fs);

                            foreach (Lead lead in leads)
                            {
                                sw.WriteLine(ConstructString(lead.RawData));
                            }

                            sw.Flush();
                            sw.Close();
                        }
                    }
                    else
                    {
                        using (FileStream fs = new FileStream(fileName, FileMode.Append))
                        {
                            sw = new StreamWriter(fs);

                            foreach (Lead lead in leads)
                            {
                                sw.WriteLine(ConstructString(lead.RawData));
                            }

                            sw.Flush();
                            sw.Close();
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw new ApplicationException("Exception occurs in generate file for DMRA", ex);
                }
                finally
                {
                    if (sw != null)
                    {
                        sw.Dispose();
                    }
                }
            }
        }

        private string ConstructString(string rawData)
        {
            StringBuilder data = new StringBuilder(string.Empty);
            data.Append(rawData.Substring(0, 9));
            data.Append(rawData.Substring(2791, 1));
            data.Append(rawData.Substring(2727, 9));
            data.Append(rawData.Substring(2819, 2));
            data.Append(rawData.Substring(2821, 2));
            data.Append(rawData.Substring(2810, 9));

            if (rawData.Substring(2791, 1) == "B")
            {
                data.Append(rawData.Substring(3107, 2));
            }
            else
            {
                data.Append(rawData.Substring(2960, 2));
            }

            return data.ToString();
        }

        /// <summary>
        /// Group the leads by block and then order the direction
        /// </summary>
        /// <param name="leads">The lead list</param>
        private List<Lead> OrderLeadsByDirection(List<Lead> leads)
        {
            List<Lead> result = new List<Lead>();
            Application objApp = new Application();
            Route objRoute;
            Map objMap;

            try
            {
                var leadgroups = from item in leads group item by new { item.LeadBlockCode } into g select g;

                foreach (var leadgroupitem in leadgroups)
                {
                    objMap = objApp.ActiveMap;
                    objRoute = objMap.ActiveRoute;
                    objApp.Visible = true;
                    objApp.UserControl = true;
                    objMap.Parent.PaneState = GeoPaneState.geoPaneRoutePlanner;
                    List<Lead> leadList = leadgroupitem.ToList<Lead>();

                    foreach (Lead lead in leadList)
                    {
                        if (lead.RawData.Substring(2791, 1).Trim() == "B")
                        {
                            lead.Latitude = lead.RawData.Substring(3169, 9).Trim();
                            lead.Longitude = lead.RawData.Substring(3178, 9).Trim();
                        }
                        else
                        {
                            lead.Latitude = lead.RawData.Substring(2972, 9).Trim();
                            lead.Longitude = lead.RawData.Substring(2981, 9).Trim();
                        }
                        //Logger.Info(lead.RawData.Substring(2972, 9) + "|" + lead.RawData.Substring(2981, 9));
                        objRoute.Waypoints.Add(objApp.ActiveMap.GetLocation(double.Parse(lead.Latitude),
                            double.Parse(lead.Longitude), 100));
                    }

                    objRoute.Calculate();
                    Logger.Info(string.Format("Calculate route for {0} leads.", leadList.Count));

                    objRoute.Waypoints.Optimize();

                    foreach (Waypoint p in objRoute.Waypoints)
                    {
                        string latitude = p.Name.Split(' ')[0];
                        string longitude = p.Name.Split(' ')[1];
                        result.AddRange(leadList.Where(c => c.Latitude == latitude && c.Longitude == longitude));
                        leadList.RemoveAll(c => c.Latitude == latitude && c.Longitude == longitude);
                    }

                    Logger.Info(string.Format("Get optimize direction order for {0} leads.", result.Count));
                }
            }
            catch (Exception ex)
            {
                Logger.Error("Exception in calculate direction order", ex);
                result = leads;
            }
            finally
            {
                objApp.ActiveMap.Saved = true;
                objApp.Quit();

                objApp = null;
            }

            return result;
        }
    }
}
